using System;
using System.Collections;
using System.Collections.Generic;

using TrueCode.Core.Diagnostics;

namespace TrueCode.Core
{
	public static class EnumerableExtension
	{
		public static IEnumerable ForEach<T>(this IEnumerable enumerable, Action<T> action)
		{
			ExceptionHelper.ThrowIfArgumentIsNull<IEnumerable>(enumerable, "enumerable");

			var array = enumerable as T[];
			if(array != null)
			{
				Array.ForEach(array, action);
			}
			else
			{
				var list = enumerable as IList< T >;
				if( list != null )
				{
					list.ForEach( action );
				}
				else
				{
					foreach( T element in enumerable )
					{
						action( element );
					}
				}
			}
			return enumerable;
		}

		public static IEnumerable ForEach(this IEnumerable enumerable, Action<object> action)
		{
			ExceptionHelper.ThrowIfArgumentIsNull<IEnumerable>(enumerable, "enumerable");

			var array = enumerable as object[];
			if(array != null)
			{
				Array.ForEach(array, action);
			}
			else
			{
				foreach(var element in enumerable)
				{
					action(element);
				}
			}
			return enumerable;
		}

		public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
		{
			ExceptionHelper.ThrowIfArgumentIsNull< IEnumerable< T > >( enumerable, "enumerable" );

			var array = enumerable as T[];
		  if( array != null )
		    Array.ForEach( array, action );
		  else
		  {
		    var list = enumerable as List< T >;
		    if( list != null )
		      list.ForEach( action );
		    else
		      foreach( var element in enumerable )
		      {
		        action( element );
		      }
		  }
		  return enumerable;
		}

    public static IEnumerable< T > Subtract< T >( this IEnumerable< T > enumerable, IEnumerable< T > subtrahend )
    {
      var minuend = new List< T >( enumerable );
      foreach( var item in subtrahend )
        minuend.Remove( item );

      return minuend;
    }
	}
}